home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / cmds / tcsh / dist / tc.bind.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-12-21  |  20.0 KB  |  943 lines

  1. /* $Header: /home/hyperion/mu/christos/src/sys/tcsh-6.01/RCS/tc.bind.c,v 3.6 1991/12/19 21:40:06 christos Exp $ */
  2. /*
  3.  * tc.bind.c: Key binding functions
  4.  */
  5. /*-
  6.  * Copyright (c) 1980, 1991 The Regents of the University of California.
  7.  * All rights reserved.
  8.  *
  9.  * Redistribution and use in source and binary forms, with or without
  10.  * modification, are permitted provided that the following conditions
  11.  * are met:
  12.  * 1. Redistributions of source code must retain the above copyright
  13.  *    notice, this list of conditions and the following disclaimer.
  14.  * 2. Redistributions in binary form must reproduce the above copyright
  15.  *    notice, this list of conditions and the following disclaimer in the
  16.  *    documentation and/or other materials provided with the distribution.
  17.  * 3. All advertising materials mentioning features or use of this software
  18.  *    must display the following acknowledgement:
  19.  *    This product includes software developed by the University of
  20.  *    California, Berkeley and its contributors.
  21.  * 4. Neither the name of the University nor the names of its contributors
  22.  *    may be used to endorse or promote products derived from this software
  23.  *    without specific prior written permission.
  24.  *
  25.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  26.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  27.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  28.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  29.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  30.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  31.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  32.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  33.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  34.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  35.  * SUCH DAMAGE.
  36.  */
  37. #include "sh.h"
  38.  
  39. RCSID("$Id: tc.bind.c,v 3.6 1991/12/19 21:40:06 christos Exp $")
  40.  
  41. #include "ed.h"
  42. #include "ed.defns.h"
  43.  
  44. static    int    str7cmp        __P((char *, char *));
  45. static    int    tocontrol    __P((int));
  46. static    char  *unparsekey    __P((int));
  47. static    KEYCMD getkeycmd    __P((Char **));
  48. static    int    parsekey        __P((Char **));
  49. static    void   printkey        __P((KEYCMD *, Char *));
  50. static    KEYCMD parsecmd        __P((Char *));
  51. static    Char  *parsestring    __P((Char *, Char *));
  52. static    void   print_all_keys    __P((void));
  53. static    void   printkeys    __P((KEYCMD *, int, int));
  54. static    void   bindkey_usage    __P((void));
  55. static    void   list_functions    __P((void));
  56. static    void   pkeys        __P((int, int));
  57.  
  58. extern int MapsAreInited;
  59.  
  60. /* like strcmp, but comparisons are striped to 7 bits
  61.    (due to shell stupidness) */
  62. static int
  63. str7cmp(a, b)
  64.     register char *a, *b;
  65. {
  66.     while ((*a & TRIM) == (*b++ & TRIM))
  67.     if (!*a++)
  68.         return (0);
  69.     b--;
  70.     return ((*a & TRIM) - (*b & TRIM));
  71. }
  72. static int
  73. tocontrol(c)
  74.     int    c;
  75. {
  76.     c &= CHAR;
  77.     if (Islower(c))
  78.     c = Toupper(c);
  79.     else if (c == ' ')
  80.     c = '@';
  81.     if (c == '?')
  82.     c = 0177;
  83.     else
  84.     c &= 037;
  85.     return (c);
  86. }
  87.  
  88. static char *
  89. unparsekey(c)            /* 'c' -> "c", '^C' -> "^" + "C" */
  90.     register int c;
  91. {
  92.     register char *cp;
  93.     static char tmp[10];
  94.  
  95.     cp = tmp;
  96.  
  97.     if (c & 0400) {
  98.     *cp++ = 'A';
  99.     *cp++ = '-';
  100.     c &= 0377;
  101.     }
  102.     if ((c & META) && !(Isprint(c) || (Iscntrl(c) && Isprint(c | 0100)))) {
  103.     *cp++ = 'M';
  104.     *cp++ = '-';
  105.     c &= ASCII;
  106.     }
  107.     if (Isprint(c)) {
  108.     *cp++ = c;
  109.     *cp = '\0';
  110.     return (tmp);
  111.     }
  112.     switch (c) {
  113.     case ' ':
  114.     (void) strcpy(cp, "Spc");
  115.     return (tmp);
  116.     case '\n':
  117.     (void) strcpy(cp, "Lfd");
  118.     return (tmp);
  119.     case '\r':
  120.     (void) strcpy(cp, "Ret");
  121.     return (tmp);
  122.     case '\t':
  123.     (void) strcpy(cp, "Tab");
  124.     return (tmp);
  125.     case '\033':
  126.     (void) strcpy(cp, "Esc");
  127.     return (tmp);
  128.     case '\177':
  129.     (void) strcpy(cp, "Del");
  130.     return (tmp);
  131.     default:
  132.     *cp++ = '^';
  133.     if (c == '\177') {
  134.         *cp++ = '?';
  135.     }
  136.     else {
  137.         *cp++ = c | 0100;
  138.     }
  139.     *cp = '\0';
  140.     return (tmp);
  141.     }
  142. }
  143.  
  144. static  KEYCMD
  145. getkeycmd(sp)
  146.     Char  **sp;
  147. {
  148.     register Char *s = *sp;
  149.     register char c;
  150.     register KEYCMD keycmd = F_UNASSIGNED;
  151.     KEYCMD *map;
  152.     int     meta = 0;
  153.     Char   *ret_sp = s;
  154.  
  155.     map = CcKeyMap;
  156.  
  157.     while (*s) {
  158.     if (*s == '^' && s[1]) {
  159.         s++;
  160.         c = tocontrol(*s++);
  161.     }
  162.     else
  163.         c = *s++;
  164.  
  165.     if (*s == '\0')
  166.         break;
  167.  
  168.     switch (map[c | meta]) {
  169.     case F_METANEXT:
  170.         meta = META;
  171.         keycmd = F_METANEXT;
  172.         ret_sp = s;
  173.         break;
  174.  
  175.     case F_XKEY:
  176.         keycmd = F_XKEY;
  177.         ret_sp = s;
  178.         /* FALLTHROUGH */
  179.  
  180.     default:
  181.         *sp = ret_sp;
  182.         return (keycmd);
  183.  
  184.     }
  185.     }
  186.     *sp = ret_sp;
  187.     return (keycmd);
  188. }
  189.  
  190. static int
  191. parsekey(sp)
  192.     Char  **sp;            /* Return position of first unparsed character
  193.                  * for return value -2 (xkeynext) */
  194. {
  195.     register int c, meta = 0, control = 0, ctrlx = 0;
  196.     Char   *s = *sp;
  197.     KEYCMD  keycmd;
  198.  
  199.     if (s == NULL) {
  200.     xprintf("bad key specification -- null string\n");
  201.     return -1;
  202.     }
  203.     if (*s == 0) {
  204.     xprintf("bad key specification -- empty string\n");
  205.     return -1;
  206.     }
  207.  
  208.     (void) strip(s);        /* trim to 7 bits. */
  209.  
  210.     if (s[1] == 0)        /* single char */
  211.     return (s[0] & 0377);
  212.  
  213.     if ((s[0] == 'F' || s[0] == 'f') && s[1] == '-') {
  214.     if (s[2] == 0) {
  215.         xprintf("Bad function-key specification.  Null key not allowed\n");
  216.         return (-1);
  217.     }
  218.     *sp = s + 2;
  219.     return (-2);
  220.     }
  221.  
  222.     if (s[0] == '0' && s[1] == 'x') {    /* if 0xn, then assume number */
  223.     c = 0;
  224.     for (s += 2; *s; s++) {    /* convert to hex; skip the first 0 */
  225.         c *= 16;
  226.         if (!Isxdigit(*s)) {
  227.         xprintf("bad key specification -- malformed hex number\n");
  228.         return -1;    /* error */
  229.         }
  230.         if (Isdigit(*s))
  231.         c += *s - '0';
  232.         else if (*s >= 'a' && *s <= 'f')
  233.         c += *s - 'a' + 0xA;
  234.         else if (*s >= 'F' && *s <= 'F')
  235.         c += *s - 'A' + 0xA;
  236.     }
  237.     }
  238.     else if (s[0] == '0' && Isdigit(s[1])) {    /* if 0n, then assume number */
  239.     c = 0;
  240.     for (s++; *s; s++) {    /* convert to octal; skip the first 0 */
  241.         if (!Isdigit(*s) || *s == '8' || *s == '9') {
  242.         xprintf("bad key specification -- malformed octal number\n");
  243.         return -1;    /* error */
  244.         }
  245.         c = (c * 8) + *s - '0';
  246.     }
  247.     }
  248.     else if (Isdigit(s[0]) && Isdigit(s[1])) {    /* decimal number */
  249.     c = 0;
  250.     for (; *s; s++) {    /* convert to octal; skip the first 0 */
  251.         if (!Isdigit(*s)) {
  252.         xprintf("bad key specification -- malformed decimal number\n");
  253.         return -1;    /* error */
  254.         }
  255.         c = (c * 10) + *s - '0';
  256.     }
  257.     }
  258.     else {
  259.     keycmd = getkeycmd(&s);
  260.  
  261.     if ((s[0] == 'X' || s[0] == 'x') && s[1] == '-') {    /* X- */
  262.         ctrlx++;
  263.         s += 2;
  264.         keycmd = getkeycmd(&s);
  265.     }
  266.     if ((*s == 'm' || *s == 'M') && s[1] == '-') {    /* meta */
  267.         meta++;
  268.         s += 2;
  269.         keycmd = getkeycmd(&s);
  270.     }
  271.     else if (keycmd == F_METANEXT && *s) {    /* meta */
  272.         meta++;
  273.         keycmd = getkeycmd(&s);
  274.     }
  275.     if (*s == '^' && s[1]) {
  276.         control++;
  277.         s++;
  278.         keycmd = getkeycmd(&s);
  279.     }
  280.     else if ((*s == 'c' || *s == 'C') && s[1] == '-') {    /* control */
  281.         control++;
  282.         s += 2;
  283.         keycmd = getkeycmd(&s);
  284.     }
  285.  
  286.     if (keycmd == F_XKEY) {
  287.         if (*s == 0) {
  288.         xprintf("Bad function-key specification.\n");
  289.         xprintf("Null key not allowed\n");
  290.         return (-1);
  291.         }
  292.         *sp = s;
  293.         return (-2);
  294.     }
  295.  
  296.     if (s[1] != 0) {    /* if symbolic name */
  297.         char   *ts;
  298.  
  299.         ts = short2str(s);
  300.         if (!str7cmp(ts, "space") || !str7cmp(ts, "Spc"))
  301.         c = ' ';
  302.         else if (!str7cmp(ts, "return") || !str7cmp(ts, "Ret"))
  303.         c = '\r';
  304.         else if (!str7cmp(ts, "newline") || !str7cmp(ts, "Lfd"))
  305.         c = '\n';
  306.         else if (!str7cmp(ts, "linefeed"))
  307.         c = '\n';
  308.         else if (!str7cmp(ts, "tab"))
  309.         c = '\t';
  310.         else if (!str7cmp(ts, "escape") || !str7cmp(ts, "Esc"))
  311.         c = '\033';
  312.         else if (!str7cmp(ts, "backspace"))
  313.         c = '\b';
  314.         else if (!str7cmp(ts, "delete"))
  315.         c = '\177';
  316.         else {
  317.         xprintf("bad key specification -- unknown name \"%s\"\n", s);
  318.         return -1;    /* error */
  319.         }
  320.     }
  321.     else
  322.         c = *s;        /* just a single char */
  323.  
  324.     if (control)
  325.         c = tocontrol(c);
  326.     if (meta)
  327.         c |= META;
  328.     if (ctrlx)
  329.         c |= 0400;
  330.     }
  331.     return (c & 0777);
  332. }
  333.  
  334.  
  335. /*ARGSUSED*/
  336. void
  337. dobindkey(v, c)
  338.     Char  **v;
  339.     struct command *c;
  340. {
  341.     KEYCMD *map;
  342.     int     ntype, no, remove;
  343.     Char   *par;
  344.     Char    p;
  345.     Char    inbuf[200];
  346.     Char    outbuf[200];
  347.     Char   *in;
  348.     Char   *out;
  349.     KEYCMD  cmd;
  350.  
  351.     if (!MapsAreInited)
  352.     ed_InitMaps();
  353.  
  354.     map = CcKeyMap;
  355.     ntype = XK_CMD;
  356.     remove = 0;
  357.     for (no = 1, par = v[no]; 
  358.      par != NULL && (*par++ & CHAR) == '-'; no++, par = v[no]) {
  359.     if ((p = (*par & CHAR)) == '-')
  360.         break;
  361.     else 
  362.         switch (p) {
  363.         case 'a':
  364.         map = CcAltMap;
  365.         break;
  366.         case 's':
  367.         ntype = XK_STR;
  368.         break;
  369.         case 'c':
  370.         ntype = XK_EXE;
  371.         break;
  372.         case 'r':
  373.         remove = 1;
  374.         break;
  375.         case 'v':
  376.         ed_InitVIMaps();
  377.         return;
  378.         case 'e':
  379.         ed_InitEmacsMaps();
  380.         return;
  381.         case 'd':
  382. #ifdef VIDEFAULT
  383.         ed_InitVIMaps();
  384. #else /* EMACSDEFAULT */
  385.         ed_InitEmacsMaps();
  386. #endif /* VIDEFAULT */
  387.         return;
  388.         case 'l':
  389.         list_functions();
  390.         return;
  391.         default:
  392.         bindkey_usage();
  393.         return;
  394.         }
  395.     }
  396.  
  397.     if (!v[no]) {
  398.     print_all_keys();
  399.     return;
  400.     }
  401.  
  402.     if ((in = parsestring(v[no++], inbuf)) == NULL)
  403.     return;
  404.     if (remove) {
  405.     if (in[1]) {
  406.         (void) DeleteXkey(in);
  407.     }
  408.     else if (map[(unsigned char) *in] == F_XKEY) {
  409.         (void) DeleteXkey(in);
  410.         map[(unsigned char) *in] = F_UNASSIGNED;
  411.     }
  412.     else {
  413.         map[(unsigned char) *in] = F_UNASSIGNED;
  414.     }
  415.     return;
  416.     }
  417.     if (!v[no]) {
  418.     printkey(map, in);
  419.     return;
  420.     }
  421.     if (v[no + 1]) {
  422.     bindkey_usage();
  423.     return;
  424.     }
  425.     switch (ntype) {
  426.     case XK_STR:
  427.     case XK_EXE:
  428.     if ((out = parsestring(v[no], outbuf)) == NULL)
  429.         return;
  430.     AddXkey(in, XmapStr(out), ntype);
  431.     map[(unsigned char) *in] = F_XKEY;
  432.     break;
  433.     case XK_CMD:
  434.     if ((cmd = parsecmd(v[no])) == 0)
  435.         return;
  436.     if (in[1]) {
  437.         AddXkey(in, XmapCmd((int) cmd), ntype);
  438.         map[(unsigned char) *in] = F_XKEY;
  439.     }
  440.     else {
  441.         (void) ClearXkey(map, in);
  442.         map[(unsigned char) *in] = cmd;
  443.     }
  444.     break;
  445.     default:
  446.     abort();
  447.     break;
  448.     }
  449. }
  450.  
  451. static void
  452. printkey(map, in)
  453.     KEYCMD *map;
  454.     Char   *in;
  455. {
  456.     unsigned char outbuf[100];
  457.     register struct KeyFuncs *fp;
  458.  
  459.     if (in[0] == 0 || in[1] == 0) {
  460.     (void) unparsestring(in, outbuf, STRQQ);
  461.     for (fp = FuncNames; fp->name; fp++) {
  462.         if (fp->func == map[(unsigned char) *in]) {
  463.         xprintf("%s\t->\t%s\n", outbuf, fp->name);
  464.         }
  465.     }
  466.     }
  467.     else {
  468.     (void) PrintXkey(in);
  469.     }
  470. }
  471.  
  472. static  KEYCMD
  473. parsecmd(str)
  474.     Char   *str;
  475. {
  476.     register struct KeyFuncs *fp;
  477.  
  478.     for (fp = FuncNames; fp->name; fp++) {
  479.     if (str7cmp(short2str(str), fp->name) == 0) {
  480.         return fp->func;
  481.     }
  482.     }
  483.     xprintf("Bad command name: %s\n", short2str(str));
  484.     return 0;
  485. }
  486.  
  487. int
  488. parseescape(ptr)
  489.     Char  **ptr;
  490. {
  491.     Char   *p, c;
  492.  
  493.     p = *ptr;
  494.  
  495.     if ((p[1] & CHAR) == 0) {
  496.     xprintf("Something must follow: %c\n", *p);
  497.     return 0;
  498.     }
  499.     if ((*p & CHAR) == '\\') {
  500.     p++;
  501.     switch (*p & CHAR) {
  502.     case 'a':
  503.         c = '\007';        /* Bell */
  504.         break;
  505.     case 'b':
  506.         c = '\010';        /* Backspace */
  507.         break;
  508.     case 't':
  509.         c = '\011';        /* Horizontal Tab */
  510.         break;
  511.     case 'n':
  512.         c = '\012';        /* New Line */
  513.         break;
  514.     case 'v':
  515.         c = '\013';        /* Vertical Tab */
  516.         break;
  517.     case 'f':
  518.         c = '\014';        /* Form Feed */
  519.         break;
  520.     case 'r':
  521.         c = '\015';        /* Carriage Return */
  522.         break;
  523.     case 'e':
  524.         c = '\033';        /* Escape */
  525.         break;
  526.     case '0':
  527.     case '1':
  528.     case '2':
  529.     case '3':
  530.     case '4':
  531.     case '5':
  532.     case '6':
  533.     case '7':
  534.         {
  535.         register int cnt, val, ch;
  536.  
  537.         for (cnt = 0, val = 0; cnt < 3; cnt++) {
  538.             ch = *p++ & CHAR;
  539.             if (ch < '0' || ch > '7') {
  540.             p--;
  541.             break;
  542.             }
  543.             val = (val << 3) | (ch - '0');
  544.         }
  545.         if ((val & 0xffffff00) != 0) {
  546.             xprintf("Octal constant does not fit in a char.\n");
  547.             return 0;
  548.         }
  549.         c = val;
  550.         --p;
  551.         }
  552.         break;
  553.     default:
  554.         c = *p;
  555.         break;
  556.     }
  557.     }
  558.     else if ((*p & CHAR) == '^') {
  559.     p++;
  560.     c = (*p == '?') ? '\177' : ((*p & CHAR) & 0237);
  561.     }
  562.     else
  563.     c = *p;
  564.     *ptr = p;
  565.     return (c);
  566. }
  567.  
  568. static Char *
  569. parsestring(str, buf)
  570.     Char   *str;
  571.     Char   *buf;
  572. {
  573.     Char   *b;
  574.     Char   *p;
  575.  
  576.     b = buf;
  577.     if (*str == 0) {
  578.     xprintf("Null string specification\n");
  579.     return 0;
  580.     }
  581.  
  582.     for (p = str; *p != 0; p++) {
  583.     if ((*p & CHAR) == '\\' || (*p & CHAR) == '^') {
  584.         if ((*b++ = parseescape(&p)) == 0)
  585.         return 0;
  586.     }
  587.     else {
  588.         *b++ = *p & CHAR;
  589.     }
  590.     }
  591.     *b = 0;
  592.     return buf;
  593. }
  594.  
  595. unsigned char *
  596. unparsestring(str, buf, sep)
  597.     Char   *str;
  598.     unsigned char *buf;
  599.     Char   *sep;
  600. {
  601.     unsigned char *b;
  602.     Char   *p;
  603.  
  604.     b = buf;
  605.     *b++ = sep[0];
  606.     if (*str == 0) {
  607.     *b++ = '^';
  608.     *b++ = '@';
  609.     *b++ = sep[1];
  610.     *b++ = 0;
  611.     return buf;
  612.     }
  613.  
  614.     for (p = str; *p != 0; p++) {
  615.     if (Iscntrl(*p)) {
  616.         *b++ = '^';
  617.         if (*p == '\177')
  618.         *b++ = '?';
  619.         else
  620.         *b++ = *p | 0100;
  621.     }
  622.     else if (*p == '^' || *p == '\\') {
  623.         *b++ = '\\';
  624.         *b++ = *p;
  625.     }
  626.     else if (*p == ' ' || (Isprint(*p) && !Isspace(*p))) {
  627.         *b++ = *p;
  628.     }
  629.     else {
  630.         *b++ = '\\';
  631.         *b++ = ((*p >> 6) & 7) + '0';
  632.         *b++ = ((*p >> 3) & 7) + '0';
  633.         *b++ = (*p & 7) + '0';
  634.     }
  635.     }
  636.     *b++ = sep[1];
  637.     *b++ = 0;
  638.     return buf;            /* should check for overflow */
  639. }
  640.  
  641. static void
  642. print_all_keys()
  643. {
  644.     int     prev, i;
  645.  
  646.     xprintf("Standard key bindings\n");
  647.     prev = 0;
  648.     for (i = 0; i < 256; i++) {
  649.     if (CcKeyMap[prev] == CcKeyMap[i])
  650.         continue;
  651.     printkeys(CcKeyMap, prev, i - 1);
  652.     prev = i;
  653.     }
  654.     printkeys(CcKeyMap, prev, i - 1);
  655.  
  656.     xprintf("Alternative key bindings\n");
  657.     prev = 0;
  658.     for (i = 0; i < 256; i++) {
  659.     if (CcAltMap[prev] == CcAltMap[i])
  660.         continue;
  661.     printkeys(CcAltMap, prev, i - 1);
  662.     prev = i;
  663.     }
  664.     printkeys(CcAltMap, prev, i - 1);
  665.     xprintf("Multi-character bindings\n");
  666.     (void) PrintXkey(STRNULL);    /* print all Xkey bindings */
  667. }
  668.  
  669. static void
  670. printkeys(map, first, last)
  671.     KEYCMD *map;
  672.     int     first, last;
  673. {
  674.     register struct KeyFuncs *fp;
  675.     Char    firstbuf[2], lastbuf[2];
  676.     unsigned char unparsbuf[10], extrabuf[10];
  677.  
  678.     firstbuf[0] = first;
  679.     firstbuf[1] = 0;
  680.     lastbuf[0] = last;
  681.     lastbuf[1] = 0;
  682.     if (map[first] == F_UNASSIGNED) {
  683.     if (first == last)
  684.         xprintf("%-15s->  is undefined\n",
  685.             unparsestring(firstbuf, unparsbuf, STRQQ));
  686.     return;
  687.     }
  688.  
  689.     for (fp = FuncNames; fp->name; fp++) {
  690.     if (fp->func == map[first]) {
  691.         if (first == last) {
  692.         xprintf("%-15s->  %s\n",
  693.             unparsestring(firstbuf, unparsbuf, STRQQ), fp->name);
  694.         }
  695.         else {
  696.         xprintf("%-4s to %-7s->  %s\n",
  697.             unparsestring(firstbuf, unparsbuf, STRQQ),
  698.             unparsestring(lastbuf, extrabuf, STRQQ), fp->name);
  699.         }
  700.         return;
  701.     }
  702.     }
  703.     if (map == CcKeyMap) {
  704.     xprintf("BUG!!! %s isn't bound to anything.\n",
  705.         unparsestring(firstbuf, unparsbuf, STRQQ));
  706.     xprintf("CcKeyMap[%d] == %d\n", first, CcKeyMap[first]);
  707.     }
  708.     else {
  709.     xprintf("BUG!!! %s isn't bound to anything.\n",
  710.         unparsestring(firstbuf, unparsbuf, STRQQ));
  711.     xprintf("CcAltMap[%d] == %d\n", first, CcAltMap[first]);
  712.     }
  713. }
  714.  
  715. static void
  716. bindkey_usage()
  717. {
  718.     xprintf(
  719.     "Usage: bindkey [options] [--] [in-string [out-string | command]]\n");
  720.     xprintf("    -a   bind key in alternative key binding\n");
  721.     xprintf("    -s   bind an out-string instead of a command\n");
  722.     xprintf("    -c   bind a unix-command instead of a command\n");
  723.     xprintf("    -v   initialized maps to default vi bindings\n");
  724.     xprintf("    -e   initialized maps to default emacs bindings\n");
  725.     xprintf("    -d   initialized maps to default bindings\n");
  726.     xprintf("    -l   list available functions with descriptions\n");
  727.     xprintf("    -r   remove the binding of in-string\n");
  728.     xprintf(
  729.        "\nIn no out-string or command is given, the binding for in-string\n");
  730.     xprintf("is printed or all bindings if in-strings is not given.\n");
  731. }
  732.  
  733. static void
  734. list_functions()
  735. {
  736.     register struct KeyFuncs *fp;
  737.  
  738.     for (fp = FuncNames; fp->name; fp++) {
  739.     xprintf("%s\n          %s\n", fp->name, fp->description);
  740.     }
  741. }
  742.  
  743. /*ARGSUSED*/
  744. void
  745. dobind(v, dummy)
  746.     register Char **v;
  747.     struct command *dummy;
  748. {
  749.     register int c;
  750.     register struct KeyFuncs *fp;
  751.     register int i, prev;
  752.     Char   *p, *l;
  753.     Char    buf[1000];
  754.  
  755.     /*
  756.      * Assume at this point that i'm given 2 or 3 args - 'bind', the f-name,
  757.      * and the key; or 'bind' key to print the func for that key.
  758.      */
  759.  
  760.     if (!MapsAreInited)
  761.     ed_InitMaps();
  762.  
  763.     if (v[1] && v[2] && v[3]) {
  764.     xprintf(
  765.        "usage: bind [KEY | COMMAND KEY | \"emacs\" | \"vi\" | \"-a\"]\n");
  766.     return;
  767.     }
  768.  
  769.     if (v[1] && v[2]) {        /* if bind FUNCTION KEY */
  770.     for (fp = FuncNames; fp->name; fp++) {
  771.         if (str7cmp(short2str(v[1]), fp->name) == 0) {
  772.         Char   *s = v[2];
  773.  
  774.         if ((c = parsekey(&s)) == -1)
  775.             return;
  776.         if (c == -2) {    /* extented key */
  777.             for (i = 0; i < 256; i++) {
  778.             if (i != 033 && (CcKeyMap[i] == F_XKEY ||
  779.                      CcAltMap[i] == F_XKEY)) {
  780.                 p = buf;
  781.                 if (i > 0177) {
  782.                 *p++ = 033;
  783.                 *p++ = i & ASCII;
  784.                 }
  785.                 else {
  786.                 *p++ = i;
  787.                 }
  788.                 for (l = s; *l != 0; l++) {
  789.                 *p++ = *l;
  790.                 }
  791.                 *p = 0;
  792.                 AddXkey(buf, XmapCmd(fp->func), XK_CMD);
  793.             }
  794.             }
  795.             return;
  796.         }
  797.         if (c & 0400) {
  798.             if (VImode) {
  799.             CcAltMap[c & 0377] = fp->func;    
  800.             /* bind the vi cmd mode key */
  801.             if (c & META) {
  802.                 buf[0] = 033;
  803.                 buf[1] = c & ASCII;
  804.                 buf[2] = 0;
  805.                 AddXkey(buf, XmapCmd(fp->func), XK_CMD);
  806.             }
  807.             }
  808.             else {
  809.             buf[0] = 030;    /* ^X */
  810.             buf[1] = c & 0377;
  811.             buf[2] = 0;
  812.             AddXkey(buf, XmapCmd(fp->func), XK_CMD);
  813.             CcKeyMap[030] = F_XKEY;
  814.             }
  815.         }
  816.         else {
  817.             CcKeyMap[c] = fp->func;    /* bind the key */
  818.             if (c & META) {
  819.             buf[0] = 033;
  820.             buf[1] = c & ASCII;
  821.             buf[2] = 0;
  822.             AddXkey(buf, XmapCmd(fp->func), XK_CMD);
  823.             }
  824.         }
  825.         return;
  826.         }
  827.     }
  828.     stderror(ERR_NAME | ERR_STRING, "Invalid function");
  829.     }
  830.     else if (v[1]) {
  831.     char   *cv = short2str(v[1]);
  832.  
  833.     if (str7cmp(cv, "list") == 0) {
  834.         for (fp = FuncNames; fp->name; fp++) {
  835.         xprintf("%s\n", fp->name);
  836.         }
  837.         return;
  838.     }
  839.     if ((str7cmp(cv, "emacs") == 0) ||
  840. #ifndef VIDEFAULT
  841.         (str7cmp(cv, "defaults") == 0) ||
  842.         (str7cmp(cv, "default") == 0) ||
  843. #endif
  844.         (str7cmp(cv, "mg") == 0) ||
  845.         (str7cmp(cv, "gnumacs") == 0)) {
  846.         /* reset keys to default */
  847.         ed_InitEmacsMaps();
  848. #ifdef VIDEFAULT
  849.     }
  850.     else if ((str7cmp(cv, "vi") == 0)
  851.          || (str7cmp(cv, "default") == 0)
  852.          || (str7cmp(cv, "defaults") == 0)) {
  853. #else
  854.     }
  855.     else if (str7cmp(cv, "vi") == 0) {
  856. #endif
  857.         ed_InitVIMaps();
  858.     }
  859.     else {            /* want to know what this key does */
  860.         Char   *s = v[1];
  861.  
  862.         if ((c = parsekey(&s)) == -1)
  863.         return;
  864.         if (c == -2) {    /* extended key */
  865.         (void) PrintXkey(s);
  866.         return;
  867.         }
  868.         pkeys(c, c);    /* must be regular key */
  869.     }
  870.     }
  871.     else {            /* list all the bindings */
  872.     prev = 0;
  873.     for (i = 0; i < 256; i++) {
  874.         if (CcKeyMap[prev] == CcKeyMap[i])
  875.         continue;
  876.         pkeys(prev, i - 1);
  877.         prev = i;
  878.     }
  879.     pkeys(prev, i - 1);
  880.     prev = 0;
  881.     for (i = 256; i < 512; i++) {
  882.         if (CcAltMap[prev & 0377] == CcAltMap[i & 0377])
  883.         continue;
  884.         pkeys(prev, i - 1);
  885.         prev = i;
  886.     }
  887.     pkeys(prev, i - 1);
  888.     (void) PrintXkey(STRNULL);    /* print all Xkey bindings */
  889.     }
  890.     return;
  891. }
  892.  
  893. static void
  894. pkeys(first, last)
  895.     register int first, last;
  896. {
  897.     register struct KeyFuncs *fp;
  898.     register KEYCMD *map;
  899.     char    buf[8];
  900.  
  901.     if (last & 0400) {
  902.     map = CcAltMap;
  903.     first &= 0377;
  904.     last &= 0377;
  905.     }
  906.     else {
  907.     map = CcKeyMap;
  908.     }
  909.     if (map[first] == F_UNASSIGNED) {
  910.     if (first == last)
  911.         xprintf(" %s\t\tis undefined\n",
  912.             unparsekey(map == CcAltMap ? first | 0400 : first));
  913.     return;
  914.     }
  915.  
  916.     for (fp = FuncNames; fp->name; fp++) {
  917.     if (fp->func == map[first]) {
  918.         if (first == last) {
  919.         xprintf(" %s\t\t%s\n",
  920.             unparsekey((first & 0377) | (map == CcAltMap ? 0400 : 0)),
  921.             fp->name);
  922.         }
  923.         else {
  924.         (void) strcpy(buf, unparsekey((first & 0377) |
  925.                           (map == CcAltMap ? 0400 : 0)));
  926.         xprintf(" %s..%s\t\t%s\n", buf,
  927.              unparsekey((last & 0377) | (map == CcAltMap ? 0400 : 0)),
  928.             fp->name);
  929.         }
  930.         return;
  931.     }
  932.     }
  933.     if (map == CcKeyMap) {
  934.     xprintf("BUG!!! %s isn't bound to anything.\n", unparsekey(first));
  935.     xprintf("CcKeyMap[%d] == %d\n", first, CcKeyMap[first]);
  936.     }
  937.     else {
  938.     xprintf("BUG!!! %s isn't bound to anything.\n",
  939.         unparsekey(first & 0400));
  940.     xprintf("CcAltMap[%d] == %d\n", first, CcAltMap[first]);
  941.     }
  942. }
  943.